<?php
/**
 * View编译并缓存
 * 
 * @package SView
 * @author Shuky
 * @since v1.0
 * @version $Id: Compile.php 82 2010-12-23 18:23:35Z shukyoo@gmail.com $
 */
namespace SView;


class Compile
{
	// view类
    protected $_view;
    
    public function __construct($view)
    {
        $this->_view = $view;
    }
    
    
    /**
     * 编译处理
     */
    public function process($viewFile, $cacheFile)
    {
        // 读取内容
        $content = $this->_fetchContent($viewFile);
        
    	// 进行区块包含编译
    	$content = $this->_parseIncludes($content);
    	// 进行变量转换编译
    	$content = $this->_parseVariables($content);
    	// 进行链接分析
    	$content = $this->_parseLink($content);
    	
    	// 如果缓存文件夹不存在，创建文件夹
		$cachePath = dirname($cacheFile);
		if (!is_dir($cachePath)) {
			$this->createDir($cachePath, 3);
		}

    	// 缓存写入
    	$this->_writeToCache($cacheFile, $content);
    }
    
    
    /**
     * 区块包含编译
     * 获取包含块内容，并写入主模板文件
     * 形式：{include file='xxx.php'}
     * @todo 自己包含自己或死循环包含问题
     */
    protected function _parseIncludes($content)
    {
        if (strpos($content, 'include')) {
        	$content = preg_replace_callback('/\{include\s*file\s*=\s*[\"\']([\w\.\/]+?)[\"\']\}/i', array($this, '_includeContent'), $content);
        }
        return $content;
    }
    /**
     * include回调：递归处理包含，并获取内容
     */
    protected function _includeContent($matches)
    {
    	$include = trim($matches[1]);
		$include = ltrim($include, '/');
    	$include = $this->_fetchContent($this->_view->getViewFile($include));
    	return $this->_parseIncludes($include);
    }
    
    
    /**
     * 变量转换编译
     * 把变量替换成静态变量值
     * 形式：{$variable}
     */
    protected function _parseVariables($content)
    {
    	return preg_replace_callback('/\{\$([\$\w]+)\}/i', array($this, '_viewVariable'), $content);
    }
    /**
     * 变量替换回调：从view中获取变量值
     */
    protected function _viewVariable($matches)
    {
		if (strpos($matches[1], '$') === 0) {
			return $this->_view->{substr($matches[1], 1)};
		} else {
			return '<?php echo $this->'. $matches[1] .'?>';
		}
    }
    
    
    /**
     * 链接分析和编译
     * 按设定的路由规则处理模板中的链接
     * 以能灵活变动路由规则而不用修改模板内容
     * 形式：{@module/controller/action?param=value}
     */
    protected function _parseLink($content)
    {
        $router = SBase\Router::getInstance();
    	return preg_replace('/\{\@(.+)\}/iU', $router->parseLink('\\1'), $content);
    }
    
    
    /**
     * 获取内容
     */
    protected function _fetchContent($file)
    {
    	if (!($content = file_get_contents($file))) {
    		throw new ViewException('模板文件"'. substr($file, strrpos($file, '/')) .'"无法读取');
    	}
    	return $content;
    }
    
    
    /**
     * 缓存写入
     */
    protected function _writeToCache($file, $content)
    {
		if (!file_put_contents($file, $content)) {
			throw new ViewException('模块缓存无法写入');
		}
    }


	/**
	 * 递归创建文件夹
	 */
	public function createDir($dirPath, $level = 3)
	{
		if (!is_dir($dirPath) && $level) {
			$this->createDir(dirname($dirPath), $level--);
			if (is_dir(dirname($dirPath))) {
				mkdir($dirPath, 0777);
			} else {
				throw new ViewException('创建文件夹失败');
			}
		}
	}
}